package helper;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.achartengine.ChartFactory;
import org.achartengine.GraphicalView;
import org.achartengine.chart.BarChart.Type;
import org.achartengine.model.XYMultipleSeriesDataset;
import org.achartengine.model.XYSeries;
import org.achartengine.renderer.SimpleSeriesRenderer;
import org.achartengine.renderer.XYMultipleSeriesRenderer;
import org.achartengine.renderer.XYSeriesRenderer;

import simpleDB.DatabaseHelper;
import simpleDB.StatisticDataObject;
import activities.StatisticsActivity.ViewState;
import activities.StatisticsActivity2;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Paint.Align;
import android.util.Log;

public class GraphFactory {
	private DatabaseHelper dbHelper;
	private Calendar dateHelper;

	private int color;

	private int axisTitleTxtSize = 20;
	private int chartTitleTxtSize = 24;
	private int lablelsTxtSize = 19;

	private List<StatisticDataObject> currStatDAOMonth = null;
	private List<StatisticDataObject> currStatDAOYear = null;

	public GraphFactory(Context c) {
		dbHelper = new DatabaseHelper(c);
		if (Settings.DISPLAY_HEIGHT <= 800) {
			lablelsTxtSize = 15;
			axisTitleTxtSize = 16;
			chartTitleTxtSize = 20;
		}
	}

	public void fetchStatisticDataObjects(ViewState v, String selectedEx,
			Calendar c) {
		Calendar cal = Calendar.getInstance();
		this.dateHelper = c;

		color = Settings.getInstance().getExerciseColor(selectedEx);
		int id = Settings.getInstance().getExerciseID(selectedEx);
		int persID = Settings.getInstance().getPersonID();

		if (v == ViewState.MONTH) {
			cal.setTime(c.getTime());
			cal.set(Calendar.DAY_OF_MONTH, 1);
			int nrDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
			this.currStatDAOMonth = new ArrayList<StatisticDataObject>(nrDays);

			for (int i = 0; i < nrDays; i++) {
				this.currStatDAOMonth.add(dbHelper
						.getRepetitions(persID, new SimpleDateFormat(
								"yyyy-MM-dd").format(cal.getTime()), id));
				cal.add(Calendar.DATE, 1);
			}
		} else if (v == ViewState.YEAR) {

			cal.setTime(c.getTime());
			if (this.currStatDAOYear == null) {
				this.currStatDAOYear = new ArrayList<StatisticDataObject>();
			}
			this.currStatDAOYear = dbHelper.getRepetionsPerMonth(persID,
					cal.get(Calendar.YEAR), id);
		}

	}

	public GraphicalView getWorkoutTimeChart(Context c, ViewState v) {
		XYMultipleSeriesDataset xy;
		XYMultipleSeriesRenderer xyR;

		if (v.equals(ViewState.MONTH)) {
			xy = getWorkoutTimeMonthDataset();
			xyR = getWorkoutTimeMonthRenderer(xy);
		} else {
			xy = getWorkoutTimeYearDataset();
			xyR = getWorkoutTimeYearRenderer(xy);
		}
		return ChartFactory.getLineChartView(c, xy, xyR);

	}

	private XYMultipleSeriesDataset getWorkoutTimeYearDataset() {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();

		XYSeries series = new XYSeries("");// WORKOUT TIME
		double lastDur = 0;
		StatisticDataObject tmp = null;
		double lastAcc = 0;
		Calendar now = Calendar.getInstance();
		int endMonth;
		int requestYear = this.dateHelper.get(Calendar.YEAR);
		int nowYear = now.get(Calendar.YEAR);
		if (requestYear >= nowYear) {
			endMonth = now.get(Calendar.MONTH) + 1;
		} else {
			endMonth = 12;
		}
		for (int j = 0; j <= endMonth; j++) {
			if (j + 1 >= currStatDAOYear.size()) {
				if (j == 0) {
					tmp = this.currStatDAOYear.get(j);
				} else {
					break;
				}
			} else {
				tmp = this.currStatDAOYear.get(j + 1);
			}
			double duration = tmp.duration;
			duration = duration / (1000.0) / (60.0) / (60.0);
			if (duration > 0) {
				series.add(j, duration);
				lastDur = duration;
			} else {
				series.add(j, lastDur);
			}
		}

		dataset.addSeries(series);
		return dataset;
	}

	private XYMultipleSeriesRenderer getWorkoutTimeYearRenderer(
			XYMultipleSeriesDataset xy) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();

		XYSeriesRenderer r1 = new XYSeriesRenderer();
		r1.setColor(color);
		r1.setLineWidth(3f);
		int xMax = 12;
		double yMax = xy.getSeriesAt(0).getMaxY();
		int yMin = (int) xy.getSeriesAt(0).getMinY();
		renderer.setXTitle("MONTH");
		renderer.setYTitle("HOURS");
		renderer.setShowLegend(false);
		renderer.setZoomEnabled(false);
		renderer.setAxisTitleTextSize(axisTitleTxtSize);
		renderer.setChartTitleTextSize(chartTitleTxtSize);
		renderer.setLabelsTextSize(lablelsTxtSize);
		renderer.setLegendTextSize(lablelsTxtSize);
		renderer.setMargins(new int[] { 20, 40,
				(int) (Settings.DISPLAY_HEIGHT * 0.07), 20 });

		renderer.setXAxisMin(-0.9);
		renderer.setYAxisMin(yMin);
		renderer.setXAxisMax(xMax);
		renderer.setYAxisMax(yMax + yMax * 0.1);
		renderer.setYLabelsAlign(Align.LEFT);

		renderer.setPanEnabled(false, false);
		renderer.setShowGrid(true);
		renderer.setGridColor(Color.GRAY);

		renderer.setXLabelsPadding(15);
		renderer.setXLabels(0); // sets the number of integer labels to appear
		for (int i = 0; i < xMax; i++) {
			renderer.addXTextLabel(i,
					Settings.getInstance().monthMapping.get(i + 1));
		}

		renderer.addSeriesRenderer(r1);

		return renderer;

	}

	private XYMultipleSeriesRenderer getWorkoutTimeMonthRenderer(
			XYMultipleSeriesDataset xy) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();
		renderer.setClickEnabled(true);
		XYSeriesRenderer r1 = new XYSeriesRenderer();
		// r1.setColor(Color.argb(200,148,90,199));
		r1.setColor(color);
		r1.setLineWidth(3f);
		int xMax = (int) xy.getSeriesAt(0).getMaxX();
		double yMax = xy.getSeriesAt(0).getMaxY();
		double yMin = xy.getSeriesAt(0).getMinY();
		renderer.setXTitle("DAY");
		renderer.setYTitle("MINUTES");
		renderer.setShowLegend(false);

		renderer.setAxisTitleTextSize(axisTitleTxtSize);
		renderer.setChartTitleTextSize(chartTitleTxtSize);
		renderer.setLabelsTextSize(lablelsTxtSize);
		renderer.setLegendTextSize(lablelsTxtSize);
		renderer.setMargins(new int[] { 10, 40,
				(int) (Settings.DISPLAY_HEIGHT * 0.07), 20 });

		renderer.setPanEnabled(true, true);
		renderer.setZoomEnabled(true, true);

		renderer.setXAxisMin(-0.9);
		renderer.setYAxisMin(yMin);
		renderer.setXAxisMax(xMax + 0.5);
		renderer.setYAxisMax(yMax + yMax * 0.1);
		renderer.setYLabelsAlign(Align.LEFT);

		renderer.setShowGrid(true);
		renderer.setGridColor(Color.GRAY);
		renderer.setXLabels(0); // sets the number of integer labels to appear
		renderer.addXTextLabel(0, "1");
		for (int i = 1; i < xMax; i++) {
			if ((i + 1) % 7 == 0)
				renderer.addXTextLabel(i, "" + (i + 1));
		}

		renderer.setXLabelsPadding(15);
		renderer.addSeriesRenderer(r1);

		return renderer;

	}

	private XYMultipleSeriesDataset getWorkoutTimeMonthDataset() {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
		XYSeries series = new XYSeries("");
		double lastDur = 0;
		int endDay;
		Calendar now = Calendar.getInstance();
		boolean c = false;
		if (now.get(Calendar.MONTH) >= this.dateHelper.get(Calendar.MONTH)) {
			endDay = now.get(Calendar.DAY_OF_MONTH);
			c = true;
		} else {
			endDay = currStatDAOMonth.size();
		}
		for (int i = 0; i <= endDay; i++) {
			// double currRps = dbHelper.getRepetitions(1, new
			// SimpleDateFormat("yyyy-MM-dd").format(cal.getTime()), id);
			if (c == false && i >= endDay)
				break;
			double ms = (double) this.currStatDAOMonth.get(i).duration;
			double min = ms / 1000.0 / 60.0;
			if (min > 0.0) {
				series.add(i, min);
				lastDur = min;
			} else {
				series.add(i, lastDur);
			}

		}

		dataset.addSeries(series);
		return dataset;
	}

	/* Repetions charts */
	public GraphicalViewWrapper getRepetitionsChart(Context c, ViewState v) {
		XYMultipleSeriesDataset xy;
		XYMultipleSeriesRenderer xyR;
		Calendar c2 = Calendar.getInstance();

		if (v.equals(ViewState.MONTH)) {
			xy = getRepsMonthDataset();
			xyR = getRepsMonthRenderer(xy);
		} else {
			xy = getRepsYearDataset();
			xyR = getRepsYearRenderer(xy);
		}
		GraphicalViewWrapper mV = new GraphicalViewWrapper(
				ChartFactory.getBarChartView(c, xy, xyR, Type.STACKED));
		if (xy.getSeriesCount() > 1) {
			mV.setDataset(xy.getSeriesAt(1));
		} else {
			mV.setDataset(xy.getSeriesAt(0));
		}
		return mV;
	}

	private XYMultipleSeriesDataset getRepsYearDataset() {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
		XYSeries tmpSeries = new XYSeries("");

		for (int j = 0; j + 1 <= 12; j++) {
			int tmp = this.currStatDAOYear.get(j + 1).repetitions;
			tmpSeries.add(j, tmp);
		}

		dataset.addSeries(tmpSeries);
		return dataset;
	}

	private XYMultipleSeriesRenderer getRepsYearRenderer(
			XYMultipleSeriesDataset xy) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();

		SimpleSeriesRenderer r = new SimpleSeriesRenderer();
		r.setColor(color);

		renderer.setClickEnabled(true);

		renderer.setShowLegend(false);
		renderer.addSeriesRenderer(r);
		renderer.setXTitle("MONTH");
		renderer.setYTitle("REACHED REPETITIONS");
		renderer.setAxisTitleTextSize(axisTitleTxtSize);
		renderer.setChartTitleTextSize(chartTitleTxtSize);
		renderer.setLabelsTextSize(lablelsTxtSize);
		renderer.setLegendTextSize(lablelsTxtSize);
		renderer.setMargins(new int[] { 10, 40,
				(int) (Settings.DISPLAY_HEIGHT * 0.07), 20 });
		int xMax = 12;
		int t = xy.getSeriesAt(0).getItemCount();
		int yMax = (int) xy.getSeriesAt(0).getMaxY();
		renderer.setXLabels(0); // sets the number of integer labels to appear
		for (int i = 1; i <= xMax; i++) {
			renderer.addXTextLabel(i - 1,
					Settings.getInstance().monthMapping.get(i));
		}

		renderer.setXAxisMin(-0.9);
		renderer.setYAxisMin(1);
		renderer.setXAxisMax(xMax);
		renderer.setYAxisMax(yMax + yMax * 0.2);
		renderer.setYLabelsAlign(Align.LEFT);
		renderer.setBarSpacing(0.3);

		renderer.setPanEnabled(false, false);
		renderer.setShowGrid(true);
		renderer.setGridColor(Color.GRAY);

		renderer.setXLabelsPadding(15);

		return renderer;

	}

	public XYMultipleSeriesRenderer getRepsMonthRenderer(
			XYMultipleSeriesDataset xy) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();

		// handle click events
		renderer.setClickEnabled(true);
		renderer.setXTitle("DAY");
		renderer.setYTitle("REACHED REPETITIONS");
		renderer.setShowLegend(false);

		// // the first dataset - representing reps to be reached
		// SimpleSeriesRenderer r = new SimpleSeriesRenderer();
		// r.setColor(getComplementaryColour(color));
		// r.setDisplayChartValues(false);
		// renderer.addSeriesRenderer(r);
		// the second dataset - actually reached reps
		SimpleSeriesRenderer r = new SimpleSeriesRenderer();
		r.setColor(color);
		r.setDisplayChartValues(false);

		renderer.addSeriesRenderer(r);

		// customize the whole renderer
		renderer.setAxisTitleTextSize(axisTitleTxtSize);
		renderer.setChartTitleTextSize(chartTitleTxtSize);
		renderer.setLabelsTextSize(lablelsTxtSize);
		renderer.setLegendTextSize(lablelsTxtSize);
		renderer.setMargins(new int[] { 10, 40,
				(int) (Settings.DISPLAY_HEIGHT * 0.07), 20 });
		// this.dateHelper.set(Calendar.DAY_OF_MONTH, 22);
		// int xMax = this.dateHelper.get(Calendar.DAY_OF_MONTH);
		int xMax = (int) xy.getSeriesAt(0).getMaxX();
		int yMax = (int) xy.getSeriesAt(0).getMaxY();
		int yMin = (int) xy.getSeriesAt(0).getMinY();
		renderer.setXLabels(0); // sets the number of integer labels to appear
		renderer.addXTextLabel(0, "1");
		for (int i = 0; i < xMax; i++) {
			if ((i + 1) % 7 == 0)
				renderer.addXTextLabel(i, "" + (i + 1));
		}
		renderer.setXAxisMin(-0.9);
		renderer.setXAxisMax(xMax + 0.5);
		renderer.setYAxisMax(yMax + yMax * 0.1);
		renderer.setYLabelsAlign(Align.LEFT);
		renderer.setBarSpacing(0.5);

		renderer.setPanEnabled(false, false);
		renderer.setZoomEnabled(false, false);
		renderer.setShowGrid(true);
		renderer.setGridColor(Color.GRAY);

		renderer.setXLabelsPadding(15);
		return renderer;
	}

	private int getComplementaryColour(int color2) {
		int r = 255 - Color.red(color2);
		int g = 255 - Color.green(color2);
		int b = 255 - Color.blue(color2);
		return Color.argb(255, r, g, b);
	}

	private XYMultipleSeriesDataset getRepsMonthDataset() {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();
		XYSeries series = new XYSeries("");
		// XYSeries repsToDo = new XYSeries("");
		int endDay;
		Calendar now = Calendar.getInstance();
		boolean c = false;
		if (now.get(Calendar.MONTH) >= this.dateHelper.get(Calendar.MONTH)) {
			endDay = now.get(Calendar.DAY_OF_MONTH);
			c = true;
		} else {
			endDay = currStatDAOMonth.size();
		}

		for (int i = 0; i <= endDay; i++) {
			if (c == false && i >= endDay)
				break;
			double currRps = this.currStatDAOMonth.get(i).repetitions;
			series.add(i, currRps);
			// TODO THIS IS ONLY FOR TESTING PURPOSES
			// if (i % 3 == 0)
			// repsToDo.add(i, (int) currRps + currRps * 0.1);
			// else {
			// repsToDo.add(i, currRps);
			// }
		}
		// dataset.addSeries(repsToDo);
		dataset.addSeries(series);
		return dataset;
	}

	/* END Repetions charts */

	public GraphicalView getAccuracyChart(Context c, ViewState v) {
		XYMultipleSeriesDataset xy;
		XYMultipleSeriesRenderer xyR = null;

		xy = getAccuracyChartDataset(v);
		xyR = getAccurayRenderer(xy, v);

		return ChartFactory.getLineChartView(c, xy, xyR);
	}

	private XYMultipleSeriesRenderer getAccurayRenderer(
			XYMultipleSeriesDataset xy, ViewState v) {
		XYMultipleSeriesRenderer renderer = new XYMultipleSeriesRenderer();

		XYSeriesRenderer r1 = new XYSeriesRenderer();
		// r1.setColor(Color.argb(200,148,90,199));
		r1.setColor(color);
		r1.setLineWidth(3f);

		// int yMax = (int) xy.getSeriesAt(0).getMaxY();
		int yMax = 100;
		renderer.setYTitle("ACCURACY as %");
		renderer.setShowLegend(false);
		renderer.setZoomEnabled(false);
		renderer.setAxisTitleTextSize(axisTitleTxtSize);
		renderer.setChartTitleTextSize(chartTitleTxtSize);
		renderer.setLabelsTextSize(lablelsTxtSize);
		renderer.setLegendTextSize(lablelsTxtSize);

		renderer.setMargins(new int[] { 10, 40,
				(int) (Settings.DISPLAY_HEIGHT * 0.07), 20 });
		renderer.setPanEnabled(false, false);

		renderer.setXAxisMin(-0.9);
		renderer.setYAxisMin(0);

		renderer.setYAxisMax(yMax + yMax * 0.1);
		renderer.setYLabelsAlign(Align.LEFT);

		renderer.setPanEnabled(false, false);
		renderer.setShowGrid(true);
		renderer.setGridColor(Color.GRAY);
		renderer.setXLabels(0); // sets the number of integer labels to appear
		int xMax = 0;
		renderer.setXLabelsPadding(15);
		if (v == ViewState.MONTH) {
			renderer.addXTextLabel(0, "1");
			renderer.setXTitle("DAY");
			xMax = (int) xy.getSeriesAt(0).getMaxX();
			for (int i = 0; i < xMax; i++) {
				if ((i + 1) % 7 == 0)
					renderer.addXTextLabel(i, "" + (i + 1));
			}
		} else if (v == ViewState.YEAR) {
			xMax = 12;
			for (int i = 0; i < xMax; i++) {
				renderer.addXTextLabel(i,
						Settings.getInstance().monthMapping.get(i + 1));
			}
		}
		renderer.setXAxisMax(xMax + 0.5);
		renderer.addSeriesRenderer(r1);

		return renderer;

	}

	private XYMultipleSeriesDataset getAccuracyChartDataset(ViewState v) {
		XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();

		XYSeries series = new XYSeries("");
		if (v == ViewState.MONTH) {
			StatisticDataObject tmp = null;
			double lastAcc = 0;
			Calendar now = Calendar.getInstance();
			int endDay = 0;
			boolean c = false;
			if (now.get(Calendar.MONTH) >= this.dateHelper.get(Calendar.MONTH)) {
				endDay = now.get(Calendar.DAY_OF_MONTH);
				c = true;
			} else {
				endDay = currStatDAOMonth.size();
			}
			for (int i = 0; i < endDay; i++) {
				if (c == false && i >= endDay)
					break;
				tmp = this.currStatDAOMonth.get(i);
				Log.i("SCROLL", "acc: " + tmp.accuracy);
				double acc = 0;
				if (tmp.repetitions > 0) {
					acc = ((double) tmp.accuracy / (double) tmp.repetitions);
					lastAcc = acc;
				} else {
					acc = lastAcc;
				}
				// acc = 0.6 + Math.random() *(0.3);
				series.add(i, acc * 100);
			}

		} else if (v == ViewState.YEAR) {
			StatisticDataObject tmp = null;
			double lastAcc = 0;
			Calendar now = Calendar.getInstance();
			int endMonth;
			int requestYear = this.dateHelper.get(Calendar.YEAR);
			int nowYear = now.get(Calendar.YEAR);
			if (requestYear >= nowYear) {
				endMonth = now.get(Calendar.MONTH) + 1;
			} else {
				endMonth = 12;
			}
			for (int j = 0; j <= endMonth; j++) {
				if (j + 1 >= currStatDAOYear.size()) {
					if (j == 0) {
						tmp = this.currStatDAOYear.get(j);
					} else {
						break;
					}
				} else {
					tmp = this.currStatDAOYear.get(j + 1);
				}
				double acc = 0;
				if (tmp.repetitions > 0) {
					acc = ((double) tmp.accuracy / (double) tmp.repetitions);
					lastAcc = acc;
				} else {
					acc = lastAcc;
				}
				series.add(j, acc * 100);

			}
		}
		dataset.addSeries(series);
		return dataset;
	}

	public void setDAO(ArrayList<StatisticDataObject> r, ViewState v) {
		if (v == ViewState.YEAR) {
			this.currStatDAOYear = r;
		} else if (v == ViewState.MONTH) {
			this.currStatDAOMonth = r;
		}
	}

}
